﻿using Agora.Rtc;
using C_Sharp_API_Example.src.Advanced.CustomRender;
using HandyControl.Tools;
using MyMeeting.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Diagnostics;
using MyMeeting.Dtos;
using MyMeeting.Extensions;

namespace MyMeeting.Service
{
    public class ShengGMeetEngine: IRtcEngineEventHandler,IMeetingEngine
    {
        private string _token;
        private string channleId;
        private string appId;
        protected IRtcEngine rtc_engine_ = null;
        private readonly string tag_ = "[CustomRender] ";
        private readonly string log_file_path = ".\\logs\\agora.log";
        private IVideoFrameObserver video_frame_observer = null;
        public System.Windows.Forms.Control view_ =null;
        private bool joined_ = false;
        private bool isOpenAudio = false;
        public List<uint> JoinUserIds;

        public List<MeetUser> Users;
        public bool AudioStatus { get => isOpenAudio; private set { } }
        public IRtcEngine Rtc { get => rtc_engine_; private set { } }
        public ShengGMeetEngine(System.Windows.Forms.Control view)
        {
            view_ = view;
            JoinUserIds = new List<uint>();
            Users = new List<MeetUser>();

        }

        public Action<uint> RemoteJoin;
        public Action<uint> RemoteLeave;
        public static List<string> GetIPv4Addresses()
        {
            string hostName = Dns.GetHostName();
            IPAddress[] addresses = Dns.GetHostAddresses(hostName);

            List<string> ipv4Addresses = new List<string>();

            foreach (IPAddress address in addresses)
            {
                // 判断是否为IPv4地址
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    ipv4Addresses.Add(address.ToString());
                }
            }
            return ipv4Addresses;
        }
        public int OpAudio()
        {
            int ret = -1;
            if (joined_ == false)
                return ret;
            if(isOpenAudio == false)
            {
              ret = Rtc.EnableAudio();
                if(ret == 0){
                    ret= Rtc.MuteLocalAudioStream(false);
                }
                isOpenAudio = ret == 0 ? true : false;
                return ret;
            }
            else
            {
                isOpenAudio = false;
                ret = Rtc.MuteLocalAudioStream(true);
                if(ret==0)
                {
                    ret= Rtc.DisableAudio();
                }
                isOpenAudio = ret == 0 ? false : true;
                return ret;
            }
        }
       public  int Init(string appId)
        {
            int ret = -1;

            if (null == rtc_engine_)
            {
                rtc_engine_ = RtcEngine.CreateAgoraRtcEngine();
            }

            // Prepare engine context
            RtcEngineContext rtc_engine_ctx = new RtcEngineContext();
            
            rtc_engine_ctx.appId = appId;
            // rtc_engine_ctx.logConfig.filePath = log_file_path;
          
            // Initialize engine
            ret = rtc_engine_.Initialize(rtc_engine_ctx);
           // MainForm.dump_handler_(tag_ + "Initialize", ret);

            // Register event handler
            ret = rtc_engine_.InitEventHandler(this);
            // MainForm.dump_handler_(tag_ + "InitEventHandler", ret);

           // Register video frame observer
            //video_frame_observer = new CustomRenderVideoFrameObserver(view_);
            //ret = rtc_engine_.RegisterVideoFrameObserver(video_frame_observer);
            //MainForm.dump_handler_(tag_ + "RegisterVideoFrameObserver", ret);

            return ret;
        }

        public  int UnInit()
        {
            if (null != rtc_engine_)
            {
                // Stop all renderer
                //view_.DestroyRender();

                // Dispose engine
                rtc_engine_.Dispose();
                rtc_engine_ = null;
            }

            return 0;
        }

       public int JoinChannel(string channelId,uint uid)
        {
            int ret = -1;
            if (null != rtc_engine_ && joined_ != true)
            {
                // Enable video module
                ret = rtc_engine_.EnableVideo();
                //MainForm.dump_handler_(tag_ + "EnableVideo", ret);

                // Start preview
                ret = rtc_engine_.StartPreview(VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA_PRIMARY);
                //MainForm.dump_handler_(tag_ + "StartPreview", ret);

                // Join channel
                ChannelMediaOptions options = new ChannelMediaOptions();
                options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
                options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
                ret = rtc_engine_.JoinChannel(this.Token, channelId, uid, options);
                var id=Rtc.MuteLocalVideoStream(false);

              //  MainForm.dump_handler_(tag_ + "JoinChannel", ret);

                joined_ = true;
            }
            return ret;
        }

        public int LeaveChannel()
        {
            int ret = -1;
            if (null != rtc_engine_ && joined_ == true)
            {
                // Stop preview
                ret = rtc_engine_.StopPreview();
               // MainForm.dump_handler_(tag_ + "StopPreview", ret);

                // Disable video module
                ret = rtc_engine_.DisableVideo();
                //  MainForm.dump_handler_(tag_ + "DisableVideo", ret);
                Rtc.MuteLocalVideoStream(true);
                // Leave channel
                ret = rtc_engine_.LeaveChannel();
                // MainForm.dump_handler_(tag_ + "LeaveChannel", ret);
                this.view_.BackColor = System.Drawing.Color.FromArgb(255, 0, 0, 0);

                joined_ = false;
            }
            return ret;
        }

        public string Token { get => _token; set => _token = value; }
        public string ChannelId { get => channleId; set => channleId = value; }
        public string AppId { get => appId; set => appId=value; }
       
        public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
        {
            base.OnJoinChannelSuccess(connection, elapsed);
            JoinUserIds.Add(connection.localUid);
            var user = new UserInfo();
             Rtc.GetUserInfoByUid(connection.localUid,ref user);
            PrismManager.CurrentUser.UserInfo = user;
            Users.Add(PrismManager.CurrentUser);
              //  RemoteJoin?.Invoke(connection.localUid);
        }
        public   override void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed)
        {
            JoinUserIds.Add(remoteUid);
            RemoteJoin?.Invoke(remoteUid);
            var user = new UserInfo();
            Rtc.GetUserInfoByUid(remoteUid, ref user);
            var meetUser = new MeetUser();
            meetUser.Id = remoteUid;
            meetUser.UserInfo = user;
            meetUser.IsOpenVideo = true;
            PrismManager.Users.Add(meetUser);
            this.Users.Add(meetUser);
        }
        public override  void OnError(int err, string msg) {

            Debug.WriteLine($"{err},{msg}");
        }
        public override void OnLeaveChannel(RtcConnection connection, RtcStats stats)
        {
            base.OnLeaveChannel(connection, stats);
            if(JoinUserIds.Contains(connection.localUid))
            {
                JoinUserIds.Remove(connection.localUid);
            }
            Users.Remove(PrismManager.CurrentUser);
        }
        public override void OnUserOffline(RtcConnection connection, uint remoteUid, USER_OFFLINE_REASON_TYPE reason)
        {
            base.OnUserOffline(connection, remoteUid, reason);

            if(JoinUserIds.Contains(remoteUid))
            {
                JoinUserIds.Remove(remoteUid);
            }
            RemoteLeave?.Invoke(remoteUid);
        }
        public override void OnUserEnableVideo(RtcConnection connection, uint remoteUid, bool enabled)
        {
            var findUser = Users.Find(a => a.Id == remoteUid);
            if (findUser != null)
            {
            findUser.IsOpenVideo = enabled;
            }

        }
        
        public override void OnUserMuteAudio(RtcConnection connection, uint remoteUid, bool muted)
        {
            base.OnUserMuteAudio(connection, remoteUid, muted);
            var findUser = Users.Find(a => a.Id == remoteUid);
            if (findUser != null)
            {
                findUser.IsOpenAudio = !muted;
            }
        }
    }
    //// override if need
    //internal class CustomRenderVideoFrameObserver : IVideoFrameObserver
    //{
    //    CustomVideoBox view_;

    //    public CustomRenderVideoFrameObserver(CustomVideoBox view)
    //    {
    //        view_ =view;
    //    }
       

    //    public override bool OnPreEncodeVideoFrame(VIDEO_SOURCE_TYPE sourceType, VideoFrame videoFrame)
    //    {
    //        view_.DeliverFrame(videoFrame);
    //        return true;
    //    }

    //    public override bool OnRenderVideoFrame(string channelId, uint remoteUid, VideoFrame videoFrame)
    //    {
    //        view_.DeliverFrame(videoFrame);
    //        return true;
    //    }

    //    public override VIDEO_OBSERVER_FRAME_TYPE GetVideoFormatPreference()
    //    {
    //        switch (view_.RenderType)
    //        {
    //            case BaseRender.CustomVideoBoxRenderType.kBufferedGraphics:
    //                return VIDEO_OBSERVER_FRAME_TYPE.FRAME_TYPE_BGRA;
    //            case BaseRender.CustomVideoBoxRenderType.kSharpDX_BGRA:
    //                return VIDEO_OBSERVER_FRAME_TYPE.FRAME_TYPE_BGRA;
    //            case BaseRender.CustomVideoBoxRenderType.kSharpDX_YUV420:
    //                return VIDEO_OBSERVER_FRAME_TYPE.FRAME_TYPE_YUV420;
    //            default:
    //                return VIDEO_OBSERVER_FRAME_TYPE.FRAME_TYPE_BGRA;
    //        }
    //    }

    //    public override VIDEO_OBSERVER_POSITION GetObservedFramePosition()
    //    {
    //        return VIDEO_OBSERVER_POSITION.POSITION_PRE_RENDERER | VIDEO_OBSERVER_POSITION.POSITION_PRE_ENCODER;
    //    }
    //}

}
